#include "SQLPropertyExpr.h"
#include <sstream>
#include "../../../utils/instanceof.h"
#include "../../SQLUtils.h"
#include "../../../utils/FnvHash.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../statement/SQLSelectItem.h"
#include "../statement/SQLColumnDefinition.h"
#include "../statement/SQLCreateProcedureStatement.h"

string_ptr SQLPropertyExpr::class_ = make_string_ptr("SQLPropertyExpr");

SQLPropertyExpr::SQLPropertyExpr(SQLExpr_ptr theOwner, string_ptr theName) : owner(theOwner)
{
  // setOwner(theOwner);
  name = theName;
}

SQLPropertyExpr::SQLPropertyExpr(string_ptr owner, string_ptr name)
    : SQLPropertyExpr(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(owner)), name)
{
}

SQLPropertyExpr::~SQLPropertyExpr()
{
}
SQLPropertyExpr::SQLPropertyExpr()
{
}

SQLPropertyExpr::SQLPropertyExpr(SQLExpr_ptr owner, string_ptr name, long nameHashCod64)
{
  setOwner(owner);
  this->name = name;
  this->nameHashCod64 = nameHashCod64;
}

string_ptr SQLPropertyExpr::getSimleName()
{
  return name;
}

string_ptr SQLPropertyExpr::getSimpleName()
{
  return name;
}

SQLExpr_ptr SQLPropertyExpr::getOwner()
{
  return owner;
}

void SQLPropertyExpr::setOwner(SQLExpr_ptr theOwner)
{
  if (owner != NULL)
  {
    owner->setParent(SharedObject(SQLPropertyExpr));
  }

  if (instanceof <SQLObject, SQLPropertyExpr>(parent))
  {
    SQLPropertyExpr_ptr propertyExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(parent);
    propertyExpr->computeHashCode64();
  }

  this->owner = owner;
  this->hashCode64_ = 0;
}

void SQLPropertyExpr::setOwner(string_ptr owner_)
{
  if (owner_->empty())
  {
    this->owner = NULL;
    return;
  }

  if (owner_->find_first_of('.') != -1)
  {
    SQLExpr_ptr ownerExpr = SQLUtils::toSQLExpr(owner_);
    this->setOwner(ownerExpr);
  }
  else
  {
    this->setOwner(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(owner_)));
  }
}

string_ptr SQLPropertyExpr::getName()
{
  return name;
}

void SQLPropertyExpr::setName(string_ptr theName)
{
  name = theName;
}

void SQLPropertyExpr::output(std::stringstream *buf)
{
  owner->output(buf);
  (*buf) << ".";
  (*buf) << *name;
}

void SQLPropertyExpr::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLPropertyExpr)))
  {
    acceptChild(visitor, owner);
  }

  visitor->endVisit(SharedObject(SQLPropertyExpr));
}

// int SQLPropertyExpr::hashCode() {
// final int prime = 31;
// int result = 1;
// result = prime * result + ((name == NULL) ? 0 : name.hashCode());
// result = prime * result + ((owner == NULL) ? 0 : owner.hashCode());
// return result;
//}

// BOOL_ptr SQLPropertyExpr::equals(Object obj) {
// if (this == obj) {
// return BOOL::TRUE;
//}
// if (obj == NULL) {
// return BOOL::FALSE;
//}
// if (!(obj instanceof SQLPropertyExpr)) {
// return BOOL::FALSE;
//}
// SQLPropertyExpr other = (SQLPropertyExpr) obj;
// if (name == NULL) {
// if (other.name != NULL) {
// return BOOL::FALSE;
//}
//} else if (!name.equals(other.name)) {
// return BOOL::FALSE;
//}
// if (owner == NULL) {
// if (other.owner != NULL) {
// return BOOL::FALSE;
//}
//} else if (!owner.equals(other.owner)) {
// return BOOL::FALSE;
//}
// return BOOL::TRUE;
//}

SQLObject_ptr SQLPropertyExpr::clone()
{
  SQLObject_ptr clone_tmp = SharedObject(SQLPropertyExpr);
  SQLPropertyExpr_ptr clone_res = std::dynamic_pointer_cast<SQLPropertyExpr>(clone_tmp);

  return clone_res;
}

long SQLPropertyExpr::nameHashCode64()
{
  return 1;
}

long SQLPropertyExpr::hashCode64()
{
  return 1;
}

SQLTableSource_ptr SQLPropertyExpr::getResolvedTableSource()
{
  if (instanceof <SQLObject, SQLTableSource>(resolvedOwnerObject))
  {
    return std::dynamic_pointer_cast<SQLTableSource>((resolvedOwnerObject));
  }

  return NULL;
}

string_ptr SQLPropertyExpr::getOwnerName()
{
  if (instanceof <SQLExpr, SQLName>(owner))
  {
    return (std::dynamic_pointer_cast<SQLName>(owner))->toString();
  }

  return make_string_ptr("");
}

BOOL_ptr SQLPropertyExpr::nameEquals(string_ptr name)
{
  return (SQLUtils::nameEquals(this->name, name))?BOOL::TRUE:BOOL::FALSE;
}

void SQLPropertyExpr::computeHashCode64()
{
  long hash;
  if (instanceof <SQLExpr, SQLName>(owner))
  {
    hash = (std::dynamic_pointer_cast<SQLName>(owner))->hashCode64();

    hash ^= '.';
    hash *= FnvHash::PRIME;
  }
  else if (owner == NULL)
  {
    hash = FnvHash::BASIC;
  }
  else
  {
    hash = FnvHash::fnv1a_64_lower(owner->toString());

    hash ^= '.';
    hash *= FnvHash::PRIME;
  }
  hash = FnvHash::hashCode64(hash, name);
  hashCode64_ = hash;
}

string_ptr SQLPropertyExpr::getOwnernName()
{
  if (instanceof <SQLExpr, SQLName>(owner))
  {
    return (std::dynamic_pointer_cast<SQLName>(owner))->toString();
  }

  return make_string_ptr("");
}

string_ptr SQLPropertyExpr::normalizedName()
{
  string_ptr ownerName;
  if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
  {
    ownerName = (std::dynamic_pointer_cast<SQLIdentifierExpr>(owner))->normalizedName();
  }
  else if (instanceof <SQLExpr, SQLPropertyExpr>(owner))
  {
    ownerName = (std::dynamic_pointer_cast<SQLPropertyExpr>(owner))->normalizedName();
  }
  else
  {
    ownerName = owner->toString();
  }

  ownerName->append(".");
  ownerName->append(*SQLUtils::normalize(name));
  return ownerName;
}

void SQLPropertyExpr::setResolvedColumn(SQLColumnDefinition_ptr resolvedColumn)
{
  this->resolvedColumn = resolvedColumn;
}
void SQLPropertyExpr::setResolvedColumn(SQLSelectItem_ptr resolvedColumn)
{
  this->resolvedColumn = resolvedColumn;
}

void SQLPropertyExpr::setResolvedOwnerObject(SQLObject_ptr resolvedOwnerObject)
{
  this->resolvedOwnerObject = resolvedOwnerObject;
}

SQLObject_ptr SQLPropertyExpr::getResolvedOwnerObject()
{
  return resolvedOwnerObject;
}

SQLCreateProcedureStatement_ptr SQLPropertyExpr::getResolvedProcudure()
{
  if (instanceof <SQLObject, SQLCreateProcedureStatement>(this->resolvedOwnerObject))
  {
    return std::dynamic_pointer_cast<SQLCreateProcedureStatement>(this->resolvedOwnerObject);
  }

  return nullptr;
}

SQLPropertyExpr_ptr SQLPropertyExpr::simplify()
{
  string_ptr normalizedName = SQLUtils::normalize(name);
  SQLExpr_ptr normalizedOwner = this->owner;
  if (instanceof <SQLExpr, SQLIdentifierExpr>(normalizedOwner))
  {
    normalizedOwner = (std::dynamic_pointer_cast<SQLIdentifierExpr>(normalizedOwner))->simplify();
  }

  if (normalizedName != name ||
      normalizedOwner != owner)
  {
    return SQLPropertyExpr_ptr(new SQLPropertyExpr(normalizedOwner, normalizedName, hashCode64_));
  }

  return SharedObject(SQLPropertyExpr);
}